package com.ssb.admin.config.shiro;


import com.ssb.admin.common.utils.ShiroUtils;
import com.ssb.admin.constant.Constants;
import com.ssb.admin.modules.sys.permission.dao.SysPermissionDao;
import com.ssb.admin.modules.sys.permission.entity.SysPermission;
import com.ssb.admin.modules.sys.role.dao.SysUserRoleDao;
import com.ssb.admin.modules.sys.role.entity.SysUserRole;
import com.ssb.admin.modules.sys.user.dao.SysUserDao;
import com.ssb.admin.modules.sys.user.entity.SysUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

@Slf4j
@Component
public class UserRealm extends AuthorizingRealm {

    private final SysUserDao sysUserDao;
    private final SysUserRoleDao sysUserRoleDao;
    private final SysPermissionDao sysPermissionDao;

    @Autowired
    public UserRealm(SysUserDao sysUserDao, SysUserRoleDao sysUserRoleDao,
                     SysPermissionDao sysPermissionDao) {
        this.sysUserDao = sysUserDao;
        this.sysUserRoleDao = sysUserRoleDao;
        this.sysPermissionDao = sysPermissionDao;
    }
    /**
     * 授权(验证权限时调用)
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 从Redis/Session读取
        if (ShiroUtils.getAuthorizationInfo() != null) {
            return (AuthorizationInfo) ShiroUtils.getAuthorizationInfo();
        }
        String loginName = (String) principals.getPrimaryPrincipal();
        SysUser sysUser = new SysUser();
        sysUser.setLoginName(loginName);
        sysUser = sysUserDao.selectOne(sysUser);

        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setUserId(sysUser.getId());
        sysUserRole = sysUserRoleDao.selectOne(sysUserRole);

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        List<String> permsList;
        if (sysUserRole == null) {
            return info;
        }
        //系统管理员，拥有最高权限
        if (sysUserRole.getRoleId().equals(Constants.USER_SADMIN)) {
            List<SysPermission> menuList = sysPermissionDao.selectList(null);
            permsList = new ArrayList<>(menuList.size());
            for (SysPermission menu : menuList) {
                permsList.add(menu.getPermission());
            }
        } else {
            List<SysPermission> menuList = sysPermissionDao.queryAllMenuItemsByRoleId(sysUserRole.getRoleId());
            permsList = new ArrayList<>(menuList.size());
            for (SysPermission menu : menuList) {
                permsList.add(menu.getPermission());
            }
        }

        //用户权限列表
        Set<String> permsSet = new HashSet<>();
        for (String perms : permsList) {
            if (StringUtils.isBlank(perms)) {
                continue;
            }
            permsSet.addAll(Arrays.asList(perms.trim().split(",")));
        }

        info.setStringPermissions(permsSet);
        // 放入Reids/Session
        ShiroUtils.setAuthorizationInfo(info);
        return info;
    }

    /**
     * 认证(登录时调用)
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken authcToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        SysUser sysUser = new SysUser();
        sysUser.setLoginName(token.getUsername());
        sysUser = sysUserDao.selectOne(sysUser);
        if (sysUser == null) {
            // 帐号不存在
            throw new UnknownAccountException();
        }
        if (sysUser.getStatus() == 1) {
            // 帐号锁定异常
            throw new LockedAccountException();
        }

        return new SimpleAuthenticationInfo(
                token.getUsername(),
                sysUser.getPassword(),
                ByteSource.Util.bytes(sysUser.getCredentialsSalt()),
                getName());
    }

    @Override
    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
        OauthHashedCredentialsMatcher shaCredentialsMatcher = new OauthHashedCredentialsMatcher();
        shaCredentialsMatcher.setHashAlgorithmName("md5");
        shaCredentialsMatcher.setHashIterations(2);
        super.setCredentialsMatcher(shaCredentialsMatcher);
    }

}
